package jp.sourceforge.akjrcp.text_douga.parser;

import java.awt.Font;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.imageio.ImageIO;

import jp.sourceforge.akjrcp.draw.DecoratedShapePainter;
import jp.sourceforge.akjrcp.ffmpeg.FFMpegFLVParser;
import jp.sourceforge.akjrcp.ffmpeg.FFMpegFileInfomation;
import jp.sourceforge.akjrcp.subtitle.srt.SRTList;
import jp.sourceforge.akjrcp.subtitle.srt.SRTObject;
import jp.sourceforge.akjrcp.subtitle.srt.SRTParser;
import jp.sourceforge.akjrcp.text_douga.AudioData;
import jp.sourceforge.akjrcp.text_douga.DougaPreference;
import jp.sourceforge.akjrcp.text_douga.DougaSystem;
import jp.sourceforge.akjrcp.text_douga.EffectData;
import jp.sourceforge.akjrcp.text_douga.ItemData;
import jp.sourceforge.akjrcp.text_douga.Messages;
import jp.sourceforge.akjrcp.text_douga.VideoData;
import jp.sourceforge.akjrcp.text_douga.audio.FileAudioData;
import jp.sourceforge.akjrcp.text_douga.audio.ZeroAudioData;
import jp.sourceforge.akjrcp.text_douga.effect.FillColorEffect;
import jp.sourceforge.akjrcp.text_douga.effect.FillImageEffect;
import jp.sourceforge.akjrcp.text_douga.effect.FrameImageEffect;
import jp.sourceforge.akjrcp.text_douga.effect.VideoEffect;
import jp.sourceforge.akjrcp.text_douga.item.AbstractItem;
import jp.sourceforge.akjrcp.text_douga.item.ColorItem;
import jp.sourceforge.akjrcp.text_douga.item.DrawingItem;
import jp.sourceforge.akjrcp.text_douga.item.GifAnimeItem;
import jp.sourceforge.akjrcp.text_douga.item.ImageItem;
import jp.sourceforge.akjrcp.text_douga.item.KaraokeItem;
import jp.sourceforge.akjrcp.text_douga.item.MultiStyledText;
import jp.sourceforge.akjrcp.text_douga.item.TextItem;
import jp.sourceforge.akjrcp.text_douga.video.ColorVideoData;
import jp.sourceforge.akjrcp.text_douga.video.CopyVideoData;
import jp.sourceforge.akjrcp.text_douga.video.EffectableVideoData;
import jp.sourceforge.akjrcp.text_douga.video.FileVideoData;
import jp.sourceforge.akjrcp.text_douga.video.ImageVideoData;
import jp.sourceforge.akjrcp.util.DownloadUtils;
import jp.sourceforge.akjrcp.util.URLDownloader;
import jp.sourceforge.akjrcp.util.YoutubeUtils;

import org.apache.commons.io.IOUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.akjava.lib.commons.time.TimeUtils;
import com.akjava.lib.commons.video.VideoUtils;

public class SimpleParser {
	public static Log log = LogFactory.getLog(SimpleParser.class);
	private File downloadedDir;
	private String ffmpegPath;//TODO can choose mediainfo
	private String youtubeDLPath;
	private String pythonPath;
	
	PropertyLine propertyLine=null;
	
	//private boolean shortest;//TODO support shortest
	private DougaSystem dougaSystem;
	private List<VideoData> videoList;
	private List<AudioData> audioList;
	
	//private File inputFile;
	private File inputDir;
	
	//default's TODO remove them.
	private float default_other_transparent=1.0f;	
	private float default_color_transparent=0.85f;	
	private double default_color_duration=1;	
	private double default_text_fadein=0;
	private double default_text_fadeout=0.05;
	private double default_image_fadein=0.1;
	private double default_image_fadeout=0.2;
	
	
	private List<ItemData> itemList;
	private List<EffectData> effectList;
	
	private boolean cancelling;
	
	private Rectangle avoidSubtitleStrategies[];
	
	//special value for export
	private double exportFPS;
	private String exportSize;
	

	private  TextDougaProperties defaultProperties=new TextDougaProperties();
	private  Map<String,PropertyLine> classPropertiesMap=new HashMap<String,PropertyLine>();
	private  TextDougaProperties currentProperties=null;
	private boolean bestQuarity=true; //for youtube-dl
	//private double moveX;
	//private double moveY;
	public SimpleParser(String ffmpegPath){
		this.ffmpegPath=ffmpegPath;
		initAvoidRect();
		
		try {
			//for first line
			currentProperties=(TextDougaProperties) defaultProperties.clone();
		} catch (CloneNotSupportedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	private void initAvoidRect() {

		List<Rectangle> rects=new ArrayList<Rectangle>();
		
//		x=right y=left w=up h=down
		for(int i=1;i<=64;i++){
			
			rects.add(new Rectangle(0,0,1*i,0));
			rects.add(new Rectangle(0,0,0,1*i));
		}
		
		for(int i=-32;i<32;i++){//
			for(int j=-32;j<32;j++){
			rects.add(new Rectangle(0,j,0,i));
			rects.add(new Rectangle(0,j,i,0));
				
			rects.add(new Rectangle(j,0,i,0));
			rects.add(new Rectangle(j,0,0,i));
			
			}
		}
		
		for(int i=64;i<=128;i++){
			//right left up down
			rects.add(new Rectangle(0,0,1*i,0));
			rects.add(new Rectangle(0,0,0,1*i));
		}
		
		
		avoidSubtitleStrategies=rects.toArray(new Rectangle[rects.size()]);
	}
	public SimpleParser(String ffmpegPath,File downloadedDir){
		this(ffmpegPath);
		this.downloadedDir=downloadedDir;
		
	}
	
	public SimpleParser(String ffmpegPath,File downloadedDir,String pythonPath,String youtubeDLPath){
		this(ffmpegPath,downloadedDir);
		this.pythonPath=pythonPath;
		this.youtubeDLPath=youtubeDLPath;
	}
	
	public void parseProperty() throws IOException{
		boolean consume=false;
		
		String pline=null;
		if(propertyLine!=null){
			pline=propertyLine.getLine();
			}
		
		if(PropertyUtils.isDefaultAction(pline)){
			if(pline.indexOf("effect")!=-1){
				log.warn("now not support any effect properties");
			}
			setProperties(defaultProperties);
			try {
				//for first line
				currentProperties=(TextDougaProperties) defaultProperties.clone();
			} catch (CloneNotSupportedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			return;
		}else if(PropertyUtils.isRestoreDefaultAction(pline)){
			defaultProperties=new TextDougaProperties();//restore
		}else if(PropertyUtils.isSetClassAction(pline)){
				try {
					TextDougaProperties newProperties=(TextDougaProperties) defaultProperties.clone();
					String name=getProperty(PropertyUtils.CLASS);
					if(name==null){
						DougaSystem.dougaLogger.warn(Messages.getString("no_class_name_defined"));
						
					}else{
					setProperties(newProperties);
					classPropertiesMap.put(name, propertyLine);
					}
					
					return;
				} catch (CloneNotSupportedException e) {
					// TODO �����������ꂽ catch �u���b�N
					e.printStackTrace();
				}
			}else if(PropertyUtils.isLoadClassAction(pline)){
				
					String name=getProperty(PropertyUtils.CLASS);
					if(name==null){
						DougaSystem.dougaLogger.warn(Messages.getString("no_class_name_defined"));
						return;
					}else{
						PropertyLine newP=classPropertiesMap.get(name);
						
						
						if(newP==null){
							DougaSystem.dougaLogger.warn(Messages.getString("class_not_setted")+":"+name);
							return;
						}else{
							TextDougaProperties newProperties;
							try {
								//parse default
								newProperties = (TextDougaProperties)defaultProperties.clone();
								PropertyLine original=propertyLine;
								//parse class
								propertyLine=newP;
								setProperties(newProperties);//parse class defined properties
								propertyLine=original;
								//parse current setted properties
								setProperties(newProperties);
								currentProperties=newProperties;
								return;
							} catch (CloneNotSupportedException e) {
								// TODO �����������ꂽ catch �u���b�N
								e.printStackTrace();
							}
							
						}
					}
				
			}
		
		//video parsing
		String video=getProperty(PropertyUtils.VIDEO);
		double duration=PropertyUtils.getDoubleValue(getProperty(PropertyUtils.DURATION),DougaSystem.FOREEVER);
		log.info("video="+video);
		VideoData videoData=null;
		if(video==null){
			
		}
		else if(ParserUtils.isColorText(video)){
			
			int color=ParserUtils.toColor(video);
			
			videoData=new ColorVideoData(color);
			videoData.setDuration(duration);
			videoList.add(videoData);

			consume=true;
			log.info(videoData);
		}else if(ParserUtils.getFileType(video)==ParserUtils.FILE_IMAGE){
			String path=ParserUtils.toFilePath(inputDir,video);
			//validate check.
			if(!new File(path).exists()){
				throw new IOException(path +" not found");
			}else{
				log.info("bgfile:"+path);
			}
			//audio..
			videoData=new ImageVideoData(path);
			videoData.setDuration(duration);
			videoList.add(videoData);
			
			consume=true;
			log.info("ImageData added");
		}
		
		 else if("copy".equals(video)){
			
			videoData=new CopyVideoData();
			videoData.setDuration(duration);
			videoList.add(videoData);
			consume=true;
		}
		else{
			log.warn("unknown video:"+video);
		}
		String audio=getProperty(PropertyUtils.AUDIO);
		log.info("audio="+audio);
		if(audio!=null){
		if(audio.equals(PropertyUtils.SILENCE)){
			ZeroAudioData zero=new ZeroAudioData();
			zero.setDuration(duration);
			if(videoData!=null){
				videoData.setAudioData(zero);
			}
			audioList.add(zero);
			consume=true;
			log.info("silenseData added,duration="+duration);
		}
		}
		//TODO show warn
		//novideo
		//noaudio
		//global property
		
		try {
			//for first line
			currentProperties=(TextDougaProperties) defaultProperties.clone();
			log.info("currentProperties copied");
		} catch (CloneNotSupportedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		//SET default old styles
		if(getProperty(PropertyUtils.DEFAULT_TEXT_FADEIN)!=null){
			default_text_fadein=PropertyUtils.getDoubleValue(getProperty(PropertyUtils.DEFAULT_TEXT_FADEIN),default_text_fadein);
		}
		
		if(getProperty(PropertyUtils.DEFAULT_TEXT_FADEOUT)!=null){
			default_text_fadeout=PropertyUtils.getDoubleValue(getProperty(PropertyUtils.DEFAULT_TEXT_FADEOUT),default_text_fadeout);
		}
		
		if(getProperty(PropertyUtils.DEFAULT_IMAGE_FADEIN)!=null){
			default_image_fadein=PropertyUtils.getDoubleValue(getProperty(PropertyUtils.DEFAULT_IMAGE_FADEIN),default_image_fadein);
		}
		
		if(getProperty(PropertyUtils.DEFAULT_IMAGE_FADEOUT)!=null){
			default_image_fadeout=PropertyUtils.getDoubleValue(getProperty(PropertyUtils.DEFAULT_IMAGE_FADEOUT),default_image_fadeout);
		}
		
		if(getProperty(PropertyUtils.DEFAULT_COLOR_DURATION)!=null){
			default_color_duration=PropertyUtils.getDoubleValue(getProperty(PropertyUtils.DEFAULT_COLOR_DURATION),default_color_duration);
		}
		
		if(getProperty(PropertyUtils.DEFAULT_COLOR_TRANSPARENT)!=null){
			default_color_transparent=PropertyUtils.getFloatValue(getProperty(PropertyUtils.DEFAULT_COLOR_TRANSPARENT),default_color_transparent);
		}
		
		if(getProperty(PropertyUtils.EXPORT_FPS)!=null){
			double exportFPS=PropertyUtils.getDoubleValue(getProperty(PropertyUtils.EXPORT_FPS),0);
			updateExportFPS(exportFPS);
		}
		
		if(getProperty(PropertyUtils.EXPORT_SIZE)!=null){
			String exportSize=PropertyUtils.getStringValue(getProperty(PropertyUtils.EXPORT_SIZE),null);
			updateExportSize(exportSize);
		}
		
		//this is special treatment consume time.
		if(getProperty(PropertyUtils.PROGRESS)!=null){
			double extraProgress=PropertyUtils.getDoubleValue(getProperty(PropertyUtils.PROGRESS),0);
			currentTime+=extraProgress;
		}
		
		//special parse draw
		if(ParserUtils.isDrawText(pline)){
			addDrawingItem(currentProperties);
			consume=true;
		}
		
		if(consume){//initialize properties or not
			consumeProperty();//remove all
		}else{
			setProperties(currentProperties);
		}
	}
	
	private void addDrawingItem(TextDougaProperties properties){
		setProperties(properties);
		DrawingItem item=new DrawingItem();

		item.setFill(properties.isFill());
		item.setLineSize(properties.getDraw_size());
		item.setColor(properties.getDraw_color());
		if(PropertyUtils.DRAW_TYPE_LINE.equals(properties.getDraw_type())){
			item.setDrawType(DrawingItem.TYPE_LINE);
		}else if(PropertyUtils.DRAW_TYPE_OVAL.equals(properties.getDraw_type())){
			item.setDrawType(DrawingItem.TYPE_OVAL);
		}else{
			item.setDrawType(DrawingItem.TYPE_RECT);
		}
		
		//other default settings.
		
		float transparent=currentProperties.parseTransparent(default_other_transparent);
		
		
		double start=currentProperties.parseStartTime(-1);//for some special treatment
		
		
		double duration=currentProperties.parseDuration(getDefaultDuration());
		
		double fadein=currentProperties.parseFadeIn(0); //TODO make default?
		double fadeout=currentProperties.parseFadeOut(0); //TODO make default?
		
		
		boolean noprogress=currentProperties.isNoProgress();
		
		if(start>=0){
			log.info("text start>=0 && noprogress");
			item.setStartTime(start);
			noprogress=true;//dont progress when time is absolute,line useless.
		}else{
			item.setStartTime(currentTime);
			}
		item.setTransparent(transparent);
		
		item.setMoveX(currentProperties.getMove_x());
		item.setMoveY(currentProperties.getMove_y());
		item.setMoveWidth(currentProperties.getMove_width());
		item.setMoveHeight(currentProperties.getMove_height());
		
		item.setDuration(duration);
		item.setFadeInTime(fadein);
		item.setFadeOutTime(fadeout);

		ItemLocationAndAlign ia=new ItemLocationAndAlign(0,0,0,0,0,ItemData.CENTER,ItemData.BOTTOM,true);
		ia.loadProperty();
		ia.setUpItem(item);
		
		
		item.setAntialiase(currentProperties.isDraw_antialiase());
		
		itemList.add(item);
		
		if(!noprogress){
			progressTime();
		}
		
	}
	
	private void setProperties(TextDougaProperties properties) {
		
		
		
		if(getProperty(PropertyUtils.LINE_FPS)!=null){
			properties.setLine_fps(PropertyUtils.getDoubleValue(getProperty(PropertyUtils.LINE_FPS),properties.getLine_fps()));
		}
		
		if(getProperty(PropertyUtils.LINE_DURATION)!=null){
			properties.setLine_duration(PropertyUtils.getDoubleValue(getProperty(PropertyUtils.LINE_DURATION),properties.getLine_duration()));
		}
		
		
		
		if(getProperty(PropertyUtils.FONT_NAME)!=null){
			properties.setFont_name(PropertyUtils.getStringValue(getProperty(PropertyUtils.FONT_NAME),properties.getFont_name()));
		}
		if(getProperty(PropertyUtils.FONT_STYLE)!=null){
			properties.setFont_style(PropertyUtils.getStringValue(getProperty(PropertyUtils.FONT_STYLE),properties.getFont_style()));
		}
		if(getProperty(PropertyUtils.FONT_SIZE)!=null){
			properties.setFont_size(PropertyUtils.getIntValue(getProperty(PropertyUtils.FONT_SIZE),properties.getFont_size()));
		}
		
		if(getProperty(PropertyUtils.TEXT_ANTIALIASE)!=null){
			properties.setText_antialiase(PropertyUtils.getBooleanValue(getProperty(PropertyUtils.TEXT_ANTIALIASE),properties.isText_antialiase()));
		}

		if(getProperty(PropertyUtils.TEXT_DRAW_LINE)!=null){
			properties.setText_draw_line(PropertyUtils.getBooleanValue(getProperty(PropertyUtils.TEXT_DRAW_LINE),properties.isText_draw_line()));
		}
		
		if(getProperty(PropertyUtils.TEXT_DRAW_BORDER)!=null){
			properties.setText_draw_border(PropertyUtils.getBooleanValue(getProperty(PropertyUtils.TEXT_DRAW_BORDER),properties.isText_draw_border()));
		}
		if(getProperty(PropertyUtils.TEXT_DRAW_SHADOW)!=null){
			properties.setText_draw_shadow(PropertyUtils.getBooleanValue(getProperty(PropertyUtils.TEXT_DRAW_SHADOW),properties.isText_draw_shadow()));
		}
		if(getProperty(PropertyUtils.TEXT_LINE_COLOR)!=null){
			properties.setText_line_color(PropertyUtils.getColorValue(getProperty(PropertyUtils.TEXT_LINE_COLOR),properties.getText_line_color()));
		}
		if(getProperty(PropertyUtils.TEXT_BORDER_COLOR)!=null){
			properties.setText_border_color(PropertyUtils.getColorValue(getProperty(PropertyUtils.TEXT_BORDER_COLOR),properties.getText_border_color()));
		}
		
		if(getProperty(PropertyUtils.TEXT_SELECT_COLOR)!=null){
			properties.setText_select_color(PropertyUtils.getColorValue(getProperty(PropertyUtils.TEXT_SELECT_COLOR),properties.getText_select_color()));
		}
		
		if(getProperty(PropertyUtils.TEXT_SHADOW_COLOR)!=null){
			properties.setText_shadow_color(PropertyUtils.getColorValue(getProperty(PropertyUtils.TEXT_SHADOW_COLOR),properties.getText_shadow_color()));
			//log.trace("shadow:"+text_shadow_color);
		}
		if(getProperty(PropertyUtils.TEXT_BORDER_SIZE)!=null){
			properties.setText_border_size(PropertyUtils.getIntValue(getProperty(PropertyUtils.TEXT_BORDER_SIZE),properties.getText_border_size()));
		}
		if(getProperty(PropertyUtils.TEXT_SHADOW_X)!=null){
			properties.setText_shadow_x(PropertyUtils.getIntValue(getProperty(PropertyUtils.TEXT_SHADOW_X),properties.getText_shadow_x()));
		}
		if(getProperty(PropertyUtils.TEXT_SHADOW_Y)!=null){
			properties.setText_shadow_y(PropertyUtils.getIntValue(getProperty(PropertyUtils.TEXT_SHADOW_Y),properties.getText_shadow_y()));
		}
		
		
		
		if(getProperty(PropertyUtils.OVERWRAP_SUBTITLE)!=null){
			properties.setOverwrap_subtitle(PropertyUtils.getBooleanValue(getProperty(PropertyUtils.OVERWRAP_SUBTITLE),properties.isOverwrap_subtitle()));
			
		}
		
		//new set
		if(getProperty(PropertyUtils.NO_PROGRESS)!=null){
			properties.setNoProgress(PropertyUtils.getBooleanValue(getProperty(PropertyUtils.NO_PROGRESS),properties.isNoProgress()));
		}
		
		if(getProperty(PropertyUtils.FADEIN)!=null){
			properties.setFadein(PropertyUtils.getDoubleValue(getProperty(PropertyUtils.FADEIN),properties.getFadein()));
		}
		if(getProperty(PropertyUtils.FADEOUT)!=null){
			properties.setFadeout(PropertyUtils.getDoubleValue(getProperty(PropertyUtils.FADEOUT),properties.getFadeout()));
		}
		if(getProperty(PropertyUtils.TRASNPARENT)!=null){
			properties.setTransparent(PropertyUtils.getPersentFloatValue(getProperty(PropertyUtils.TRASNPARENT),properties.getTransparent()));
		}
		if(getProperty(PropertyUtils.DURATION)!=null){
			properties.setDuration(PropertyUtils.getDoubleValue(getProperty(PropertyUtils.DURATION),properties.getDuration()));
		}
		if(getProperty(PropertyUtils.START)!=null){
			properties.setStart(PropertyUtils.getDoubleValue(getProperty(PropertyUtils.START),properties.getStart()));
		}
		
		if(getProperty(PropertyUtils.X)!=null){
			properties.setX(PropertyUtils.getIntValue(getProperty(PropertyUtils.X),properties.getX()));
		}
		if(getProperty(PropertyUtils.Y)!=null){
			properties.setY(PropertyUtils.getIntValue(getProperty(PropertyUtils.Y),properties.getY()));
		}
		if(getProperty(PropertyUtils.Z)!=null){
			properties.setZ(PropertyUtils.getIntValue(getProperty(PropertyUtils.Z),properties.getZ()));
		}
		
		
		if(getProperty(PropertyUtils.LOOP)!=null){
			properties.setLoop(PropertyUtils.getIntValue(getProperty(PropertyUtils.LOOP),properties.getLoop()));
		}
		if(getProperty(PropertyUtils.WIDTH)!=null){
			properties.setWidth(PropertyUtils.getIntValue(getProperty(PropertyUtils.WIDTH),properties.getWidth()));
		}
		if(getProperty(PropertyUtils.HEIGHT)!=null){
			properties.setHeight(PropertyUtils.getIntValue(getProperty(PropertyUtils.HEIGHT),properties.getHeight()));
		}	
		if(getProperty(PropertyUtils.MOVE_X)!=null){
			properties.setMove_x(PropertyUtils.getIntValue(getProperty(PropertyUtils.MOVE_X),properties.getMove_x()));
		}
		if(getProperty(PropertyUtils.MOVE_Y)!=null){
			properties.setMove_y(PropertyUtils.getIntValue(getProperty(PropertyUtils.MOVE_Y),properties.getMove_y()));
		}
		if(getProperty(PropertyUtils.MOVE_W)!=null){
			properties.setMove_width(PropertyUtils.getIntValue(getProperty(PropertyUtils.MOVE_W),properties.getMove_width()));
		}
		if(getProperty(PropertyUtils.MOVE_H)!=null){
			properties.setMove_height(PropertyUtils.getIntValue(getProperty(PropertyUtils.MOVE_H),properties.getMove_height()));
		}
		
		if(getProperty(PropertyUtils.SHEAR_X)!=null){
			properties.setShear_x(PropertyUtils.getDoubleValue(getProperty(PropertyUtils.SHEAR_X),properties.getShear_x()));
		}
		if(getProperty(PropertyUtils.SHEAR_Y)!=null){
			properties.setShear_y(PropertyUtils.getDoubleValue(getProperty(PropertyUtils.SHEAR_Y),properties.getShear_y()));
		}
		
		if(getProperty(PropertyUtils.MOVE_ROTATE)!=null){
			properties.setMove_rotate(PropertyUtils.getIntValue(getProperty(PropertyUtils.MOVE_ROTATE),properties.getMove_rotate()));
		}
		if(getProperty(PropertyUtils.ROTATE)!=null){
			properties.setRotate(PropertyUtils.getIntValue(getProperty(PropertyUtils.ROTATE),properties.getRotate()));
		}
		
		if(getProperty(PropertyUtils.ALIGN)!=null){
			String avalue=PropertyUtils.getStringValue(getProperty(PropertyUtils.ALIGN),"");
			int align=properties.getAlign();
			if(avalue.equals(PropertyUtils.ALIGN_CENTER)){
				align=ImageItem.CENTER;
			}else if(avalue.equals(PropertyUtils.ALIGN_LEFT)){
				align=ImageItem.LEFT;
			}else if(avalue.equals(PropertyUtils.ALIGN_RIGHT)){
				align=ImageItem.RIGHT;
			}
			//log.trace(""+align);
			properties.setAlign(align);
		}
		if(getProperty(PropertyUtils.VALIGN)!=null){
			String vvalue=PropertyUtils.getStringValue(getProperty(PropertyUtils.VALIGN),"");
			int valign=properties.getValign();;
			if(vvalue.equals(PropertyUtils.VALIGN_CENTER)){
				valign=ImageItem.MIDDLE;
			}else if(vvalue.equals(PropertyUtils.VALIGN_MIDDLE)){
				valign=ImageItem.MIDDLE;
			}else if(vvalue.equals(PropertyUtils.VALIGN_TOP)){
				valign=ImageItem.TOP;
			}else if(vvalue.equals(PropertyUtils.VALIGN_BOTTOM)){
				valign=ImageItem.BOTTOM;
			}
			properties.setValign(valign);
		}
		
		if(getProperty(PropertyUtils.TEXT_TIMING)!=null){
			properties.setTiming((PropertyUtils.getStringValue(getProperty(PropertyUtils.TEXT_TIMING),properties.getTiming())));
		}
		if(getProperty(PropertyUtils.TEXT_TYPE)!=null){
			properties.setText_type((PropertyUtils.getStringValue(getProperty(PropertyUtils.TEXT_TYPE),properties.getText_type())));
		}
		
		//new set
		if(getProperty(PropertyUtils.KEEP_ASPECT)!=null){
			properties.setKeepAspect((PropertyUtils.getBooleanValue(getProperty(PropertyUtils.KEEP_ASPECT),properties.isKeepAspect())));
		}
		
		//for draw
		//new set
		if(getProperty(PropertyUtils.FILL)!=null){
			properties.setFill((PropertyUtils.getBooleanValue(getProperty(PropertyUtils.FILL),properties.isFill())));
		}
		
		if(getProperty(PropertyUtils.DRAW_TYPE)!=null){
			properties.setDraw_type((PropertyUtils.getStringValue(getProperty(PropertyUtils.DRAW_TYPE),properties.getDraw_type())));
		}
		
		if(getProperty(PropertyUtils.DRAW_SIZE)!=null){
			properties.setDraw_size(PropertyUtils.getIntValue(getProperty(PropertyUtils.DRAW_SIZE),properties.getDraw_size()));
		}
		
		if(getProperty(PropertyUtils.DRAW_COLOR)!=null){
			properties.setDraw_color(PropertyUtils.getColorValue(getProperty(PropertyUtils.DRAW_COLOR),properties.getDraw_color()));
		}
		
		if(getProperty(PropertyUtils.DRAW_ANTIALIASE)!=null){
			properties.setDraw_antialiase(PropertyUtils.getBooleanValue(getProperty(PropertyUtils.DRAW_ANTIALIASE),properties.isDraw_antialiase()));
		}
	}
	private void updateExportFPS(double fps) {
		dougaSystem.getVideoSystem().getDougaPreference().setFps(fps);
		dougaSystem.getAudioSystem().getDougaPreference().setFps(fps);
	}
	private void updateExportSize(String size){
		if(size==null){
			return;
		}
		int w_h[]=VideoUtils.sizeToWidthHeight(size);
		if(w_h!=null){
			dougaSystem.getVideoSystem().getDougaPreference().setWidth(w_h[0]);
			dougaSystem.getVideoSystem().getDougaPreference().setHeight(w_h[1]);
			dougaSystem.getAudioSystem().getDougaPreference().setWidth(w_h[0]);
			dougaSystem.getAudioSystem().getDougaPreference().setHeight(w_h[1]);
		}
	}
	double currentTime=0;
	
	private boolean redownload;
	private FFMpegFLVParser fileInfoParser;
	//private Map videoInfos=new HashMap();
	private URLDownloader downloader;
	
	public void progressTime(){
		currentTime+=currentProperties.getLine_fps();
	}
	
	
	public DougaSystem parseTextDouga(File textd) throws IOException{
		String text=IOUtils.toString(new FileReader(textd));
		return parseTextDouga(text,textd.getParentFile());
	}
	
		public DougaSystem parseTextDouga(String text,File dir) throws IOException{
			return parseTextDouga(text,dir,null);
		}
		public DougaSystem parseTextDouga(String text,File dir,DougaPreference preference) throws IOException{
		inputDir=dir;
		dougaSystem = new DougaSystem();
		if(preference!=null){
			dougaSystem.getVideoSystem().setDougaPreference(preference);
			dougaSystem.getAudioSystem().setDougaPreference(preference);
		}
		dougaSystem.setFfmpegPath(ffmpegPath);//very important
		
		videoList = new ArrayList<VideoData>();
		audioList = new ArrayList<AudioData>();
		itemList = new ArrayList<ItemData>();
		effectList = new ArrayList<EffectData>();
		
		DataLine[] dataLines=ParserUtils.parseDataLines(inputDir, text);
		
		
		//gather resources.
		//download FLV
		//download MP3 or images.
		//get resource
		int downloadItem=0;//for progress bar
		for (int i = 0; i < dataLines.length; i++) {
			if(dataLines[i] instanceof URLLine){
				URLLine urlLine=(URLLine)dataLines[i];
				if(YoutubeUtils.isYoutubeVideoURL(urlLine.getLine())){
					//download..
					urlLine.setAbsolutePath(downloadedDir+"\\youtube.com\\"+YoutubeUtils.toFLVFileName(new URL(urlLine.getLine())));
					//set
				}else{
					urlLine.setAbsolutePath(DownloadUtils.toDownloadFile(downloadedDir, new URL(urlLine.getLine())).getAbsolutePath());
				}
				downloadItem++;
				
			}
			
			if(cancelling){
				
				return null;
			}
		}
		
		for (int i = 0; i < dataLines.length; i++) {
			if(dataLines[i] instanceof URLLine){
				URLLine urlLine=(URLLine)dataLines[i];
				
				//check file
				File saveFile=new File(urlLine.getAbsolutePath());
				if(saveFile.exists() && saveFile.length()>0 && !redownload){
					//don't download them.
				}else{
					if((youtubeDLPath==null || youtubeDLPath.length()==0 || !new File(youtubeDLPath).exists())&& YoutubeUtils.isYoutubeVideoURL(urlLine.getLine())){
						DougaSystem.dougaLogger.error(Messages.getString("textdouga.need_youtubedl"));
						throw new IOException("youtube dl not found");
					}else{
					//log.warn(youtubeDLPath+","+(youtubeDLPath==null) +","+ YoutubeUtils.isYoutubeURL(urlLine.getLine()));
					DougaSystem.dougaLogger.info(Messages.getString("textdouga.start_download")+":"+urlLine.getLine());
					downloader = new URLDownloader();
					downloader.setBestQuarity(bestQuarity);
					downloader.setPythonPath(pythonPath);
					downloader.setYoutubeDLPath(youtubeDLPath);
					saveFile.getParentFile().mkdirs();//for save dir.
					downloader.download(new URL(urlLine.getLine()), saveFile);//youtube-dl need directory
					DougaSystem.dougaLogger.info(Messages.getString("textdouga.finish_download")+":"+saveFile.getName());
					downloader=null;
					//TODO done progress.
					}
				}
				
				if(cancelling){
					
					return null;
				}
			}
		}
		
		
		
		//debug
		for (int i = 0; i < dataLines.length; i++) {
			log.info("item:"+dataLines[i]);
		}
		
		
		fileInfoParser = new FFMpegFLVParser(ffmpegPath);
		for (int i = 0; i < dataLines.length; i++) {
			if(dataLines[i] instanceof URLLine){
				URLLine urlLine=(URLLine) dataLines[i];
				parseURLLine(urlLine);
				consumeProperty();
			}else
			if(dataLines[i] instanceof PropertyLine){
				propertyLine=(PropertyLine) dataLines[i];
				parseProperty();
				//don't consume
			}else if(dataLines[i] instanceof ColorLine){
				parseColorLine((ColorLine)dataLines[i]);
				consumeProperty();
			}else if(dataLines[i] instanceof CommentLine){
				//just commnet
				log.info(dataLines[i]);
//				don't consume
			}else if(dataLines[i] instanceof EmptyLine){
				progressTime();
				consumeProperty();
			}else if(dataLines[i] instanceof FileLine){
				FileLine fileLine=(FileLine)dataLines[i];
				parseFileLine(fileLine);
				consumeProperty();
			}else if(dataLines[i] instanceof TextLine){
				parseTextLine((TextLine) dataLines[i]);
				consumeProperty();//
			}
		}
		
		//time check
		double totalVideo=0;
		double totalAudio=0;
		
		double totalItem=0;//TODO care item times.
		
		//add
		Iterator<VideoData> iter=videoList.iterator();
		while(iter.hasNext()){
			VideoData data=iter.next();
			dougaSystem.getVideoSystem().addVideoData(data);
			if(totalVideo!=DougaSystem.FOREEVER){
				double v=data.getTotalTime();
				if(v!=DougaSystem.FOREEVER){
					totalVideo+=v;
				}else{
					totalVideo=DougaSystem.FOREEVER;
				}
			}
		}
		
		Iterator<AudioData> iter2=audioList.iterator();
		while(iter2.hasNext()){
			AudioData data=iter2.next();
			dougaSystem.getAudioSystem().addAudioData(data);
			if(totalAudio!=DougaSystem.FOREEVER){
				double v=data.getTotalTime();
				if(v!=DougaSystem.FOREEVER){
					totalAudio+=v;
				}else{
					totalAudio=DougaSystem.FOREEVER;
				}
			}
		}
		
		Iterator<ItemData> iter3=itemList.iterator();
		while(iter3.hasNext()){
			dougaSystem.getVideoSystem().addItemData(iter3.next());
		}
		
		Iterator<EffectData> iter4=effectList.iterator();
		while(iter4.hasNext()){
			dougaSystem.getVideoSystem().addEffectData(iter4.next());
		}
		
		log.info("videoDatas:"+dougaSystem.getVideoSystem().getVideoDatas().length);
		VideoData[] videos=dougaSystem.getVideoSystem().getVideoDatas();
		for (int i = 0; i < videos.length; i++) {
			log.trace("("+(i+1)+")"+videos[i]);
		}
		
		log.info("audioDatas:"+dougaSystem.getAudioSystem().getAudioDatas().length);
		AudioData[] audios=dougaSystem.getAudioSystem().getAudioDatas();
		for (int i = 0; i < audios.length; i++) {
			log.trace("("+(i+1)+")"+audios[i]);
		}
		
		log.info("itemDatas:"+dougaSystem.getVideoSystem().getSortedItemDatas().length);
		ItemData[] items=dougaSystem.getVideoSystem().getSortedItemDatas();
		for (int i = 0; i < items.length; i++) {
			log.trace("("+(i+1)+")"+items[i]);
		}
		
		
		log.info("videoLength:"+totalVideo);
		log.info("audioLength:"+totalAudio);
		if(totalVideo==0 && totalAudio==0){//novideo and no audio
			double lastTime=getLastItemTime();
			if(lastTime>0){//valid item
				ColorVideoData data=new ColorVideoData(0);
				data.setDuration(DougaSystem.FOREEVER);
				dougaSystem.getVideoSystem().addVideoData(data);
				totalVideo=DougaSystem.FOREEVER;
			}
		}
		

		if(totalVideo==DougaSystem.FOREEVER && totalAudio==DougaSystem.FOREEVER){
			double lastTime=getLastItemTime();
			if(lastTime==0){
				throw new IOException("audio & video both play forever");
				}
			else{
				dougaSystem.getVideoSystem().setMaxTime(lastTime);
				dougaSystem.getAudioSystem().setMaxTime(lastTime);
			}
			
		}
	
		else if(totalVideo==DougaSystem.FOREEVER){
			if(totalAudio==0){
				double lastTime=getLastItemTime();
				if(lastTime==0){
					throw new IOException("forever play video need audio");
					}
				else{
					dougaSystem.getVideoSystem().setMaxTime(lastTime);
				}
			
			}else{
			dougaSystem.getVideoSystem().setMaxTime(totalAudio);
			}
		}
		
		else if(totalAudio==DougaSystem.FOREEVER){
			if(totalVideo==0){
				double lastTime=getLastItemTime();
				if(lastTime==0){
					throw new IOException("forever play audio need video");
					}
				else{
					//insert default black
					ColorVideoData data=new ColorVideoData(0);
					data.setDuration(lastTime);
					dougaSystem.getVideoSystem().addVideoData(data);
					dougaSystem.getAudioSystem().setMaxTime(lastTime);
				}
				
				}
			else{
			dougaSystem.getAudioSystem().setMaxTime(totalVideo);
			}
		}else if(totalVideo==0){//audio only //BUG TODO
			double lastTime=getLastItemTime();
			if(lastTime>0){//valid item
				log.info("audio and item data:add video");
				
				ColorVideoData data=new ColorVideoData(0);
				data.setDuration(totalAudio);
				
				dougaSystem.getVideoSystem().addVideoData(data);
				totalVideo=totalAudio;
			}
		}
		log.info("totalAudio:="+totalAudio+" totalVideo="+totalVideo);
		//set effect time
		
		Iterator<VideoData> tmpIter=videoList.iterator();
		double currentTime=0;
		double fps=dougaSystem.getVideoSystem().getDougaPreference().getFps();
		LOOP:while(tmpIter.hasNext()){
			VideoData data=tmpIter.next();
			EffectableVideoData effectable=null;
			if(data instanceof EffectableVideoData){
				effectable=(EffectableVideoData)data;
			}
			
			if(effectable!=null && effectable.getStartEffect()!=null){
				int keyFrame=(int) (currentTime*fps+1);
				effectable.getStartEffect().setKeyFrame(keyFrame);
				log.trace("start:"+keyFrame);
			}
			
			double v=data.getTotalTime();
			if(v!=DougaSystem.FOREEVER){
				int frames=(int) (v*fps);
				log.trace("v="+v+",fps="+dougaSystem.getVideoSystem().getDougaPreference().getFps()+" = "+(v*dougaSystem.getVideoSystem().getDougaPreference().getFps()));
				log.trace("frames="+frames+","+data);
				currentTime+=v;
				if(effectable!=null && effectable.getEndEffect()!=null){
					int keyFrame=(int) (currentTime*fps+1);
					effectable.getEndEffect().setKeyFrame(keyFrame);
					log.trace("end:"+(keyFrame));
				}
				
				
			}else{
				//FOREVER
				double duration=dougaSystem.getVideoSystem().getMaxTime()-currentTime;
				int keyFrame=(int) ((float)duration*fps);
				
				if(effectable!=null && effectable.getEndEffect()!=null){
					effectable.getEndEffect().setKeyFrame(keyFrame);
					log.trace("end:"+(keyFrame));
				}
				break LOOP;//no more videos.
			}
			
		}
		
		log.info("effectDatas:"+dougaSystem.getVideoSystem().getEffectDatas().length);
		EffectData[] effects=dougaSystem.getVideoSystem().getEffectDatas();
		for (int i = 0; i < effects.length; i++) {
			log.trace("("+(i+1)+")"+effects[i]);
		}
		
		//System.exit(0);
		
		//can handel time?
		//safety zone.
		if(totalVideo>60*60 || totalAudio>60*60){
			throw new IOException("audio or video is too long ,now support under 30 minute for safety");
		}
		
		
		return dougaSystem;
	}
		/**
		 * 
		 * @param line
		 * color property is
		 * start,duration,transparent
		 */
	private double getLastItemTime(){
		double last=0;
		Iterator<ItemData> iter3=itemList.iterator();
		while(iter3.hasNext()){
			ItemData data=iter3.next();
			last=Math.max(last, data.getLastTime());
			//dougaSystem.getVideoSystem().addItemData();
		}
		return last;
	}
	private void parseColorLine(ColorLine line) {
		double start=currentProperties.parseStartTime(currentTime);
			
		double duration=currentProperties.parseDuration(getDefaultDuration());
		float transparent=currentProperties.parseTransparent(default_color_transparent);
		double fadein=currentProperties.parseFadeIn(0.2); //TODO make default?
		double fadeout=currentProperties.parseFadeOut(0.2); //TODO make default?
		
		ColorItem item=new ColorItem(line.getColor(),transparent);
		item.setStartTime(start);
		item.setDuration(duration);
		item.setFadeInTime(fadein);
		item.setFadeOutTime(fadeout);
		itemList.add(item);
		
		processProgressTime();
	}
	
	
	private void processProgressTime(){
		if(!currentProperties.isNoProgress() && currentProperties.getStart()<0){
			progressTime();
		}
	}
	
	public void parseURLLine(URLLine urlLine) throws IOException{
		String path=urlLine.getAbsolutePath();
		int type=ParserUtils.getFileType(urlLine.getAbsolutePath());
		if(type==ParserUtils.FILE_VIDEO){
			parseVideoFile(new File(path));
		}else if(type==ParserUtils.FILE_AUDIO){
			parseAudioFile(new File(path));
		}else if(type==ParserUtils.FILE_IMAGE){
			parseImageFile(new File(path));
			
			processProgressTime();
		}
	}
	
	public void parseAudioFile(File file){
		double start=currentProperties.getStart();
		double duration=currentProperties.getDuration();;
		int loop=currentProperties.getLoop();;
		
		
		//TODO mediaInfo
		FFMpegFileInfomation info=parseFileInfomation(file);
		
		FileAudioData adata=new FileAudioData(file.getAbsolutePath());
		adata.setStartTime(start);
		adata.setDuration(duration);
		adata.setLoop(loop);
		

		adata.setLogicalTime(TimeUtils.toMillisecond(info.getDuration(),true)/1000.0);
		audioList.add(adata);
	}
	
	private Map<String,FFMpegFileInfomation> fileInfoMap=new HashMap<String,FFMpegFileInfomation>();
	
	private FFMpegFileInfomation parseFileInfomation(File file){
		FFMpegFileInfomation info=fileInfoMap.get(file.getAbsolutePath());
		if(info==null){
			info=fileInfoParser.parseFile(file);
			fileInfoMap.put(file.getAbsolutePath(), info);
		}
		return info;
	}
	public void parseVideoFile(File file) throws IOException{
		double start=currentProperties.getStart();
		
		double duration=currentProperties.getDuration();;
		int loop=currentProperties.getLoop();
		
		
		boolean addVideo=true;
		boolean addAudio=true;	//if it's has
		
		String v=getProperty(PropertyUtils.NOVIDEO);
		String a=getProperty(PropertyUtils.NOAUDIO);
		//TODO
		/*
		 * boolean isNoAudio=isNoAudio();
		 * **insert Zero at online. 
		 * 
		 */
		
		int x=currentProperties.getX();
		int y=currentProperties.getY();
		int w=currentProperties.getWidth();
		int h=currentProperties.getHeight();
		if(a!=null){
			addAudio=false;
		}
		
		if(v!=null){
			addVideo=false;
		}
		
		//anytime add video
		FFMpegFileInfomation info=parseFileInfomation(file);
		
		
		FileVideoData fdata=null;
		if(addVideo){
			if(!info.isHaveVideo()){
				log.trace(fileInfoParser.getLogText());
				throw new IOException("no video wrong file:");
				
			}
		
		fdata=new FileVideoData(file.getAbsolutePath());
		fdata.setBounds(x,y,w,h);
		
		fdata.setStartTime(start);
		fdata.setDuration(duration);
		fdata.setLoop(loop);
		videoList.add(fdata);
		fdata.setLogicalTime(TimeUtils.toMillisecond(info.getDuration(),true)/1000.0);
		
		parseVideoEffect(fdata);
		}
		
		if(addAudio){
		if(info.isHaveAudio()){
			FileAudioData adata=new FileAudioData(file.getAbsolutePath());
			adata.setStartTime(start);
			adata.setDuration(duration);
			adata.setLoop(loop);
			
			adata.setLogicalTime(TimeUtils.toMillisecond(info.getDuration(),true)/1000.0);
			audioList.add(adata);
			
			if(fdata!=null){
				fdata.setAudioData(adata);//this means synch
			}
		}else{
			log.warn("this video has no audio:"+file.getAbsolutePath());
		}
		}
	}
	private void parseVideoEffect(FileVideoData fdata) {
		//TODO move effect to properties.
		int effect=PropertyUtils.getIntValue(getProperty(PropertyUtils.EFFECT), 0);
		int start_effect=PropertyUtils.getIntValue(getProperty(PropertyUtils.START_EFFECT),0);
		int end_effect=PropertyUtils.getIntValue(getProperty(PropertyUtils.END_EFFECT), 0);
		
		double effect_before=PropertyUtils.getDoubleValue(getProperty(PropertyUtils.EFFECT_BEFORE),0.2);
		double effect_after=PropertyUtils.getDoubleValue(getProperty(PropertyUtils.EFFECT_AFTER),0.2);
		double effect_full=PropertyUtils.getDoubleValue(getProperty(PropertyUtils.EFFECT_FULL),0.1);
		
		
		int color=PropertyUtils.getColorValue(getProperty(PropertyUtils.EFFECT_COLOR), 0);//default is black
		File imageFile=PropertyUtils.getFileValue(getProperty(PropertyUtils.EFFECT_IMAGE),inputDir, null);
		BufferedImage image=null;
		if(imageFile!=null){
			try {
				ImageIO.read(imageFile);
			} catch (IOException e) {
			
				e.printStackTrace();
			}
		}
		
		if(effect>0){
			VideoEffect videoEffect=null;
			switch(effect){
			case 1:		//frame
				//no frame in effect all
				break;
			case 2:		//color
				videoEffect=new FillColorEffect(color);
				break;
			case 3:		//image
				if(image!=null){
					videoEffect=new FillImageEffect(image);
				}
				break;
			}
			if(videoEffect!=null){
				videoEffect.setMode(DougaSystem.FOREEVER);
				if(!(videoEffect instanceof FrameImageEffect)){	//FrameImageEffect don't need.
					videoEffect.setBeforeTime(effect_before);
					videoEffect.setAfterTime(effect_after);
					videoEffect.setFullEffectTime(effect_full);
					}
				effectList.add(videoEffect);
			}
		}else if(effect<0){
			//audio
			//TODO
		}
		
		if(start_effect>0){
			
			VideoEffect videoEffect=null;
			switch(start_effect){
			case 1:		//frame
				//no frame in effect all
				videoEffect=new FrameImageEffect(false,effect_after);
				break;
			case 2:		//color
				videoEffect=new FillColorEffect(color);
				break;
			case 3:		//image
				if(image!=null){
					videoEffect=new FillImageEffect(image);
				}
				break;
			}
			if(videoEffect!=null){
				if(!(videoEffect instanceof FrameImageEffect)){	//FrameImageEffect don't need.
					videoEffect.setBeforeTime(effect_before);
					videoEffect.setAfterTime(effect_after);
					videoEffect.setFullEffectTime(effect_full);
					}
				fdata.setStartEffect(videoEffect);
				effectList.add(videoEffect);
			}
		}else if(start_effect<0){
			//audio
			//TODO
		}
		
		if(end_effect>0){
			VideoEffect videoEffect=null;
			switch(end_effect){
			case 1:		//frame
				//no frame in effect all
				//now it didn't support
				//videoEffect=new FrameImageEffect(true,effect_before);
				break;
			case 2:		//color
				videoEffect=new FillColorEffect(color);
				break;
			case 3:		//image
				if(image!=null){
					videoEffect=new FillImageEffect(image);
				}
				break;
			}
			if(videoEffect!=null){
				if(!(videoEffect instanceof FrameImageEffect)){	//FrameImageEffect don't need.
				videoEffect.setBeforeTime(effect_before);
				videoEffect.setAfterTime(effect_after);
				videoEffect.setFullEffectTime(effect_full);
				}
				fdata.setEndEffect(videoEffect);
				effectList.add(videoEffect);
			}
		}else if(end_effect<0){
			//audio
			//TODO
		}
		
	}
	public void parserDirectoryFile(File dir){

		//TODO support forever
		int loop=currentProperties.getLoop();
		if(loop<=0){
			log.info("wrong loop:"+getProperty(PropertyUtils.LOOP));
			loop=1;
		}
		double start=currentProperties.parseStartTime(currentTime);
		double duration=currentProperties.parseDuration(1);;//TODO make default?
		double wait=PropertyUtils.getDoubleValue(getProperty(PropertyUtils.WAIT),0.1);//TODO default,TODO move properties.
		
		double fadein=currentProperties.parseFadeIn(0.2); //TODO make default?
		double fadeout=currentProperties.parseFadeOut(0.2); //TODO make default?
		double transparent=currentProperties.parseTransparent(default_other_transparent);
	
		
		String list[]=dir.list();
		double time=start;
		
		int added=0;
		if(list!=null){
			ItemLocationAndAlign ia=new ItemLocationAndAlign(0,0,0,0,0,ItemData.CENTER,ItemData.CENTER,true);
			ia.loadProperty();
			
			for(int i=0;i<loop;i++){
			for (int j = 0; j < list.length; j++) {
				if(ParserUtils.getFileType(list[j])==ParserUtils.FILE_IMAGE){
					//show slide show.
					ImageItem item=createImageItem(new File(dir,list[j]),1);//dir didn't loop
					
					ia.setUpItem(item);
					
					item.setStartTime(time);
					item.setDuration(duration);
					item.setTransparent((float) transparent);
					item.setFadeInTime(fadein);
					item.setFadeOutTime(fadeout);
					
					item.setMoveX(currentProperties.getMove_x());
					item.setMoveY(currentProperties.getMove_y());
					item.setMoveWidth(currentProperties.getMove_width());
					item.setMoveHeight(currentProperties.getMove_height());
					
					itemList.add(item);
					added++;
					log.info("start="+time+" duration="+duration+" img="+item.getInputPath());
					time+=duration+wait;
				}
			}
			}
		}else{
			log.warn("list null:"+dir);
		}
		log.info("add dir images "+added+ " as item overray="+transparent);
	
	
	}
	public void parseFileLine(FileLine fileLine) throws IOException{
		int type=ParserUtils.getFileType(fileLine.getAbsolutePath());
		if(type==ParserUtils.FILE_VIDEO){
			parseVideoFile(fileLine.getFile());
		}else if(type==ParserUtils.FILE_DIRECTORY){
			parserDirectoryFile(fileLine.getFile());
		}else if(type==ParserUtils.FILE_AUDIO){
			parseAudioFile(fileLine.getFile());
		}else if(type==ParserUtils.FILE_IMAGE){
			parseImageFile(fileLine.getFile());
		}else if(type==ParserUtils.FILE_SUBTTILE){
			parseSubtitleFile(fileLine.getFile());
		}
		consumeProperty();
	}
	
	
	private ImageItem createImageItem(File imageFile,int loop){
		if(imageFile.getName().toLowerCase().endsWith(".gif")){
			GifAnimeItem item=new GifAnimeItem();
			item.setLoop(loop);
			item.setInputPath(imageFile.getAbsolutePath());
			return item;
		}else{
			ImageItem item=new ImageItem();
			item.setInputPath(imageFile.getAbsolutePath());
			return item;
		}
	}
	
	private double getDefaultDuration(){
		double default_d=defaultProperties.getLine_fps();
		if(defaultProperties.getLine_duration()>0){
			default_d=defaultProperties.getLine_duration();
		}
		return default_d;
	}
	
	private void parseSubtitleFile(File file) {
		double start_offset=currentProperties.getStart();
		String type=currentProperties.getText_type();
		
		//TextItem defaultItem=new TextItem("");
	
		ItemLocationAndAlign ia=new ItemLocationAndAlign(0,0,0,0,0,ItemData.CENTER,ItemData.BOTTOM,true);
		ia.loadProperty();
		//ia.setUpItem(defaultItem);
	

		
		//setUpTextDecoration(defaultItem);
		double fadein=currentProperties.parseFadeIn(default_text_fadein); //TODO make default?
		double fadeout=currentProperties.parseFadeOut(default_text_fadeout); //TODO make default?
		float transparent=currentProperties.parseTransparent(default_other_transparent);
		
		
		
		
		SRTParser parser=new SRTParser();
		try {
			SRTList srtList=parser.parse(new FileReader(file));
			for (int i = 0; i < srtList.size(); i++) {
				SRTObject srt=srtList.getSRTObjectAt(i);
				TextItem item;
				if(type.equals(PropertyUtils.TEXT_TYPE_KARAOKE)){
					item=new KaraokeItem("");
				}else{
					item=new TextItem("");
				}
				ia.setUpItem(item);
				//
				item.setTransparent(transparent);//
				if(srt.getText()!=null){//srt parse ignore start with \n
					log.info("'"+srt.getText()+"'");
				item.setText(srt.getText());
				double stime=(double)srt.getStart().getTime()/1000+start_offset;
				double etime=(double)srt.getEnd().getTime()/1000+start_offset;
				
				item.setStartTime(stime);
				item.setDuration(etime-stime);
				//check location
				List<TextItem> beforeText=new ArrayList<TextItem>();
				for(int j=itemList.size()-1;j>=0;j--){
					if(itemList.get(j) instanceof TextItem){
						TextItem tmp=(TextItem)itemList.get(j);
						if(AbstractItem.isOverwrapTime(item, tmp)){
							beforeText.add(tmp);
						}
					}
				}
				item.setFadeInTime(fadein);
				item.setFadeOutTime(fadeout);
				
				item.setMoveX(currentProperties.getMove_x());
				item.setMoveY(currentProperties.getMove_y());
				item.setMoveWidth(currentProperties.getMove_width());
				item.setMoveHeight(currentProperties.getMove_height());
				
				setUpTextDecoration(item);
				if(!currentProperties.isOverwrap_subtitle()){//not allow overwrap subtitles.
					resetRect(item,beforeText);
				}
				itemList.add(item);
				}
				
			}
		} catch (FileNotFoundException e) {
			e.printStackTrace();
			DougaSystem.dougaLogger.error("srt:problem "+file.getAbsolutePath());
			return;
		}
		//System.exit(1);
	}

	private void resetRect(TextItem item,List<TextItem> textItems){
		int expand=6;
		int moved=10;
		if(textItems.size()==0){
			return;
		}
		log.trace("same item:"+textItems.size());
		
		BufferedImage tmpImage=new BufferedImage(1,1,BufferedImage.TYPE_INT_RGB);
		Graphics2D g2=(Graphics2D) tmpImage.getGraphics();
		//g2.setFont(item.getFont());
		item.initializeShape(g2, dougaSystem.getVideoSystem().getDougaPreference());
		Rectangle current=item.getDrawRect(dougaSystem.getVideoSystem().getDougaPreference(), tmpImage);
		log.trace("current:"+current);
		Rectangle[] otherRects=new Rectangle[textItems.size()];
		
		for (int i = 0; i < otherRects.length; i++) {
			TextItem text=textItems.get(i);
			text.initializeShape(g2, dougaSystem.getVideoSystem().getDougaPreference());
			//get Layouted Image
			otherRects[i]=text.getDrawRect(dougaSystem.getVideoSystem().getDougaPreference(), tmpImage);
			otherRects[i].x-=expand;
			otherRects[i].y-=expand;
			otherRects[i].width+=expand*2;
			otherRects[i].height+=expand*2;
		}
		boolean faild=false;
		boolean changed=false;
		boolean avoided=false;
		int strategy=0;
		Rectangle checkRect=new Rectangle(current);
		while(!avoided){
			//log.trace(checkRect);
			avoided=true;
			if(!inScreen(checkRect)){
				//log.trace("not in");
				avoided=false;
			}
			
			if(avoided){
			CHECK:for (int i = 0; i < otherRects.length; i++) {
				if(checkRect.intersects(otherRects[i])){
					avoided=false;
					break CHECK;
				}
			}
			}
			
			if(!avoided){
				log.trace("strategy:"+avoidSubtitleStrategies[strategy]);
				checkRect=new Rectangle(current);
				checkRect.x+=moved*avoidSubtitleStrategies[strategy].x;//right
				checkRect.x-=moved*avoidSubtitleStrategies[strategy].y;//left
				
				checkRect.y+=moved*avoidSubtitleStrategies[strategy].width;//top
				checkRect.y-=moved*avoidSubtitleStrategies[strategy].height;//bottom
				//log.trace("minus="+current.height*avoidSubtitleStrategies[strategy].height);
				log.trace("new check:"+checkRect);
				
				changed=true;
				strategy++;
				if(strategy==avoidSubtitleStrategies.length){
					log.warn("give uped avoid rect");
					faild=true;
					break;
				}
			}
		}
		
		if(changed&&!faild){
			log.trace("moved:"+checkRect);
			//MOVE ON!
			item.setAlign(TextItem.NONE);
			item.setValign(TextItem.NONE);
			item.setX(checkRect.x);
			item.setY(checkRect.y);
			item.setWidth(checkRect.width+expand*2);
			item.setHeight(checkRect.height);
			item.clear();
		}
		
		tmpImage.getGraphics().dispose();
	}
	private boolean inScreen(Rectangle rect){
		int w=dougaSystem.getVideoSystem().getDougaPreference().getWidth();
		int h=dougaSystem.getVideoSystem().getDougaPreference().getHeight();
		log.trace(w+"x"+h);
		log.trace((rect.x+rect.width)+"x"+(rect.y+rect.height));
		//maybe have problem with font.
		if(rect.x<0 || rect.y<0){
			return false;
		}
		
		if(rect.x+rect.width>w || rect.y+rect.height>h){
			return false;
		}
		
		return true;
	}
	private void parseImageFile(File file) {
		double start=currentProperties.parseStartTime(currentTime);
		
		
		double duration=currentProperties.parseDuration(getDefaultDuration());
		
		double fadein=currentProperties.parseFadeIn(default_image_fadein); //TODO make default?
		double fadeout=currentProperties.parseFadeOut(default_image_fadeout); //TODO make default?
		float transparent=currentProperties.parseTransparent(default_other_transparent);
		
		//log.trace(fadein+","+fadeout);
		int loop=currentProperties.getLoop();
		if(loop<1){
			loop=1;
		}
		ImageItem item=createImageItem(file,loop);
		item.setStartTime(start);
		
		item.setMoveX(currentProperties.getMove_x());
		item.setMoveY(currentProperties.getMove_y());
		item.setMoveWidth(currentProperties.getMove_width());
		item.setMoveHeight(currentProperties.getMove_height());

		int defaultValign=ItemData.NONE;
		int defaultAlign=ItemData.NONE;
		//TODO think default
		ItemLocationAndAlign ia=new ItemLocationAndAlign(0,0,0,0,0,defaultAlign,defaultValign,true);
		ia.loadProperty();
		ia.setUpItem(item);
	//	setItemLocation(item,0,0,0,0,1); //image little bit draw back.
		
		//setItemAlignValign(item,ItemData.CENTER,ItemData.CENTER);
		

		item.setDuration(duration);//duration 4?
		item.setTransparent((float) transparent);
		item.setFadeInTime(fadein);
		item.setFadeOutTime(fadeout);
		
		itemList.add(item);
		
		
		processProgressTime();
		
	}
	/*
	private void setItemAlignValign(AbstractItem item,int defaultAlign,int defaultValign){
		int align=defaultAlign;
		int valign=defaultValign;
		
		if(getProperty(PropertyUtils.X)!=null){
			align=ImageItem.NONE;
		}
		if(getProperty(PropertyUtils.Y)!=null){
			valign=ImageItem.NONE;
		}
		String avalue=PropertyUtils.getStringValue(getProperty(PropertyUtils.ALIGN),"");
		if(avalue.equals(PropertyUtils.ALIGN_CENTER)){
			align=ImageItem.CENTER;
		}else if(avalue.equals(PropertyUtils.ALIGN_LEFT)){
			align=ImageItem.LEFT;
		}else if(avalue.equals(PropertyUtils.ALIGN_RIGHT)){
			align=ImageItem.RIGHT;
		}
		
		String vvalue=PropertyUtils.getStringValue(getProperty(PropertyUtils.VALIGN),"");
		if(vvalue.equals(PropertyUtils.VALIGN_CENTER)){
			valign=ImageItem.MIDDLE;
		}else if(vvalue.equals(PropertyUtils.VALIGN_MIDDLE)){
			valign=ImageItem.MIDDLE;
		}else if(vvalue.equals(PropertyUtils.VALIGN_TOP)){
			valign=ImageItem.TOP;
		}else if(vvalue.equals(PropertyUtils.VALIGN_BOTTOM)){
			valign=ImageItem.BOTTOM;
		}
		
		item.setAlign(align);
		item.setValign(valign);
	}*/
	public void parseTextLine(TextLine textline){
		
		
		float transparent=currentProperties.parseTransparent(default_other_transparent);
		
		
		double start=currentProperties.parseStartTime(-1);//for some special treatment
		
		
		double duration=currentProperties.parseDuration(getDefaultDuration());
		
		double fadein=currentProperties.parseFadeIn(default_image_fadein); //TODO make default?
		double fadeout=currentProperties.parseFadeOut(default_image_fadeout); //TODO make default?
		
		
		boolean noprogress=currentProperties.isNoProgress();
		
		String type=currentProperties.getText_type();
		
		
		
		if(type.equals(PropertyUtils.TEXT_TYPE_NORMAL)){
		
		TextItem item=new TextItem(textline.getText());
		if(start>=0){
			log.info("text start>=0 && noprogress");
			item.setStartTime(start);
			noprogress=true;//dont progress when time is absolute,line useless.
		}else{
			item.setStartTime(currentTime);
		}
		item.setTransparent(transparent);
		
		item.setMoveX(currentProperties.getMove_x());
		item.setMoveY(currentProperties.getMove_y());
		item.setMoveWidth(currentProperties.getMove_width());
		item.setMoveHeight(currentProperties.getMove_height());
		
		item.setDuration(duration);
		item.setFadeInTime(fadein);
		item.setFadeOutTime(fadeout);
		
		item.setShearX(currentProperties.getShear_x());
		item.setShearY(currentProperties.getShear_y());
		item.setRotate(currentProperties.getRotate());
		item.setMoveRotate(currentProperties.getMove_rotate());
		//TODO
		//font
		
		//decoration
		
		//location
		//setItemLocation(item,0,0,0,0,0);
		
		//layout
		//setItemAlignValign(item,ItemData.CENTER,ItemData.BOTTOM);

		ItemLocationAndAlign ia=new ItemLocationAndAlign(0,0,0,0,0,ItemData.CENTER,ItemData.BOTTOM,true);
		ia.loadProperty();
		ia.setUpItem(item);
		
		setUpTextDecoration(item);
		
		if(isMultiStyledText(textline.getText())){
		parseMultiStyledText(item);	
		}else{
		itemList.add(item);
		}
		}else if(type.equals(PropertyUtils.TEXT_TYPE_KARAOKE)){//KARAOKE
			
			log.trace("type:"+type);
			KaraokeItem item=new KaraokeItem(textline.getText());
			double[] timing=PropertyUtils.getTimingValue(currentProperties.getTiming(), null);
			item.setTiming(timing);
			
			if(start>=0){
				item.setStartTime(start);
				noprogress=true;//dont progress when time is absolute
			}else{
				item.setStartTime(currentTime);
			}
			
			item.setTransparent(transparent);
			item.setMoveX(currentProperties.getMove_x());
			item.setMoveY(currentProperties.getMove_y());
			item.setMoveWidth(currentProperties.getMove_width());
			item.setMoveHeight(currentProperties.getMove_height());
			
			
			item.setDuration(duration);
			item.setFadeInTime(fadein);
			item.setFadeOutTime(fadeout);

			log.trace(currentProperties.getAlign()+","+currentProperties.getValign());
			ItemLocationAndAlign ia=new ItemLocationAndAlign(0,0,0,0,0,ItemData.CENTER,ItemData.BOTTOM,true);
			ia.loadProperty();
			ia.setUpItem(item);
			
			//
			//item.setAlign(currentProperties.parseAlign(ItemData.CENTER)); 
			//item.setValign(currentProperties.parseValign(ItemData.BOTTOM)); 
			
			setUpTextDecoration(item);
			
			itemList.add(item);
		}
		if(!noprogress){
			progressTime();
		}
	}
	
	
	Pattern multiStyledTextPattern = Pattern.compile("(.*?)\\{\\{(.+?) (.+?) \\}\\}");
	private void parseMultiStyledText(TextItem item) {
		MultiStyledText mText=new MultiStyledText(item);
		//keep just layout?
		
		
		Matcher matcher = multiStyledTextPattern.matcher(item.getText());
		
		String remain=null;
		while (matcher.find()) {
		 log.info("muched:"+matcher.group(1)+","+matcher.group(2)+","+matcher.group(3));
		 if(matcher.group(1).length()>0){
		 TextItem preItem=new TextItem(item,matcher.group(1));
		 preItem.setAlign(ItemData.NONE);
		 preItem.setValign(ItemData.NONE);
		 mText.addTextItem(preItem);//add normal text.
		 
		 //NOW temporary two line separate only support
		 //TODO fix it.
		 if(preItem.getText().equals("\\n")){
			 log.trace("muched");
			 preItem.setText(" \n");
		 }
		 else if(preItem.getText().equals("\\n\\n")){
			 log.trace("muched");
			 preItem.setText(" \n\n");
		 }
		 
		 }
		 
		 
		
		 
		 TextItem newItem=new TextItem(item,matcher.group(3));
		
		 setTextPropertyFromClass(newItem,matcher.group(2));
		 newItem.setAlign(ItemData.NONE);	//layout must be NONE
		 newItem.setValign(ItemData.NONE);
			
		 mText.addTextItem(newItem);
		 remain=item.getText().substring(matcher.end());//remaining Text.
		}
		
		if(remain==null){
			log.warn("pattern much faild:"+item.getText());
		}else if(remain.length()>0){
			
			TextItem newItem=new TextItem(item,remain);
			newItem.setAlign(ItemData.NONE);
			newItem.setValign(ItemData.NONE);
			mText.addTextItem(newItem);
		}
		
		
		
		itemList.add(mText);
	}
	private void setTextPropertyFromClass(TextItem item, String name) {

			PropertyLine newP=classPropertiesMap.get(name);
			
			
			if(newP==null){
				DougaSystem.dougaLogger.warn(Messages.getString("class_not_setted")+":"+name);
				return;
			}else{
				TextDougaProperties newProperties;
				try {
					
					//parse default
					newProperties = (TextDougaProperties)currentProperties.clone();
					PropertyLine original=propertyLine;
					//parse class
					propertyLine=newP;
					setProperties(newProperties);//parse class defined properties
					
					propertyLine=original;//back to origin.
					
					/*
					float transparent=newProperties.parseTransparent(default_other_transparent);
					
					
					double start=newProperties.parseStartTime(-1);//for some special treatment
					item.setStartTime(start);
					
					
					double duration=newProperties.parseDuration(getDefaultDuration());
					
					double fadein=newProperties.parseFadeIn(default_image_fadein); //TODO make default?
					double fadeout=newProperties.parseFadeOut(default_image_fadeout); //TODO make default?
					
					item.setTransparent(transparent);
					
					item.setMoveX(newProperties.getMove_x());
					item.setMoveY(newProperties.getMove_y());
					item.setMoveWidth(newProperties.getMove_width());
					item.setMoveHeight(newProperties.getMove_height());
					
					item.setDuration(duration);
					item.setFadeInTime(fadein);
					item.setFadeOutTime(fadeout);
					
					item.setShearX(newProperties.getShear_x());
					item.setShearY(newProperties.getShear_y());
					item.setRotate(newProperties.getRotate());
					item.setMoveRotate(newProperties.getMove_rotate());
					//TODO
					//font
					
					//decoration
					
					//location
					//setItemLocation(item,0,0,0,0,0);
					
					//layout
					//setItemAlignValign(item,ItemData.CENTER,ItemData.BOTTOM);

					ItemLocationAndAlign ia=new ItemLocationAndAlign(newProperties.getX(),newProperties.getY(),newProperties.getZ(),newProperties.getWidth(),newProperties.getHeight(),newProperties.getAlign(),newProperties.getValign(),true);
					ia.loadProperty();
					
					//ia.setUpItem(item);
					
					//
					 * */
					TextDougaProperties originP=currentProperties;
					currentProperties=newProperties;
					setUpTextDecoration(item);
					currentProperties=originP;
					return;
				} catch (CloneNotSupportedException e) {
					// TODO �����������ꂽ catch �u���b�N
					e.printStackTrace();
				}
				
			}
		
		
	}
	private boolean isMultiStyledText(String text) {
		return text.indexOf("{{")!=-1 && text.indexOf(" }}")!=-1;
	}
	public void setUpTextDecoration(TextItem item){
		int fontStyle=Font.PLAIN;
		if(currentProperties.getFont_style().equals(PropertyUtils.FONT_STYLE_BOLD)){
			fontStyle=Font.BOLD;
		}else if(currentProperties.getFont_style().equals(PropertyUtils.FONT_STYLE_ITALIC)){
			fontStyle=Font.ITALIC;
		}else if(currentProperties.getFont_style().equals(PropertyUtils.FONT_STYLE_BOLD_ITALIC)){
			fontStyle=Font.BOLD|Font.ITALIC;
		}
		Font font=new Font(currentProperties.getFont_name(),fontStyle,currentProperties.getFont_size());
		item.setFont(font);
		
		DecoratedShapePainter decoration=item.getDecoratedShapePainter();
		decoration.setAntialiase(currentProperties.isText_antialiase());
		decoration.setAntialiaseShadow(currentProperties.isText_antialiase());
		decoration.setFillColor(currentProperties.getText_line_color());
		decoration.setLineColor(currentProperties.getText_border_color());
		decoration.setLineSize(currentProperties.getText_border_size()*2);
		decoration.setShadowColor(currentProperties.getText_shadow_color());
		decoration.setShadowOffsetX(currentProperties.getText_shadow_x());
		decoration.setShadowOffsetY(currentProperties.getText_shadow_y());
		decoration.setSelectColor(currentProperties.getText_select_color());
		
		decoration.setFill(currentProperties.isText_draw_line());
		decoration.setLine(currentProperties.isText_draw_border());
		decoration.setShadow(currentProperties.isText_draw_shadow());
		
		
	}
	/*
	private void setItemLocation(AbstractItem item,int dx, int dy, int dw, int dh, int dz) {
		int x=PropertyUtils.getIntValue(getProperty(PropertyUtils.X),dx);
		int y=PropertyUtils.getIntValue(getProperty(PropertyUtils.Y),dy);
		
		int width=PropertyUtils.getIntValue(getProperty(PropertyUtils.WIDTH),dw);
		int height=PropertyUtils.getIntValue(getProperty(PropertyUtils.HEIGHT),dh);
		
		int z=PropertyUtils.getIntValue(getProperty(PropertyUtils.Z),dz);
		item.setBounds(x,y,width,height);
		item.setZ(z);	
	}*/
	
	public class ItemLocationAndAlign{
		private int x;
		private int y;
		private int z;
		private int width;
		private int height;
		private int align;
		private int valign;
		private boolean keepAspect;
		
		
		
		public boolean isKeepAspect() {
			return keepAspect;
		}
		public void setKeepAspect(boolean keepAspect) {
			this.keepAspect = keepAspect;
		}
		/**
		 * 
		 * @param x
		 * @param y
		 * @param z
		 * @param width
		 * @param height
		 * @param align
		 * @param valign
		 * @param keepAspect
		 */
		public ItemLocationAndAlign(int x,int y,int z,int width,int height,int align,int valign,boolean keepAspect){
			this.x=x;
			this.y=y;
			this.z=z;
			this.width=width;
			this.height=height;
			this.align=align;
			this.valign=valign;
			this.keepAspect=keepAspect;
		}
		public void setUpItem(AbstractItem item){
			item.setBounds(x,y,width,height);
			item.setZ(z);
			item.setKeepAspect(keepAspect);
			
			item.setAlign(align);
			item.setValign(valign);
			
		}
		public void loadProperty(){
			x=currentProperties.getX();
			y=currentProperties.getY();
			
			width=currentProperties.getWidth();
			height=currentProperties.getHeight();
			
			z=currentProperties.getZ();
			
			keepAspect=currentProperties.isKeepAspect();
			
			//this is special treatment.
			/*
			if(getProperty(PropertyUtils.X)!=null){
				align=ItemData.NONE;
			}else{
				align=currentProperties.parseAlign(this.align); 
					
			}*/
			align=currentProperties.parseAlign(this.align);
			
			/*
			if(getProperty(PropertyUtils.Y)!=null){
				valign=ItemData.NONE;//TODO this is for imageItems
			}else{
				//use default if valigin is empty(0)
				
			}*/
			valign=currentProperties.parseValign(this.valign); 
			
		}
		public int getAlign() {
			return align;
		}
		public void setAlign(int align) {
			this.align = align;
		}
		public int getHeight() {
			return height;
		}
		public void setHeight(int height) {
			this.height = height;
		}
		public int getValign() {
			return valign;
		}
		public void setValign(int valign) {
			this.valign = valign;
		}
		public int getWidth() {
			return width;
		}
		public void setWidth(int width) {
			this.width = width;
		}
		public int getX() {
			return x;
		}
		public void setX(int x) {
			this.x = x;
		}
		public int getY() {
			return y;
		}
		public void setY(int y) {
			this.y = y;
		}
		public int getZ() {
			return z;
		}
		public void setZ(int z) {
			this.z = z;
		}
	
	
	}
	public void consumeProperty(){
		propertyLine=null;
		try {
			//for first line
			currentProperties=(TextDougaProperties) defaultProperties.clone();
		} catch (CloneNotSupportedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	public String getProperty(String key){
		if(propertyLine==null){
			return null;
		}else{
			return propertyLine.getValue(key);
		}
	}
	public boolean isCancelling() {
		return cancelling;
	}
	public void setCancelling(boolean cancelling) {
		this.cancelling = cancelling;
		if(cancelling && downloader!=null){
			try {
				downloader.cancel();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}
}
